/*
 * Copyright (c) 2017-2019, Lindenis Tech. Ltd.
 * All rights reserved.
 *
 * File:
 *
 * Description:
 *
 * Author:
 *      xiaoshujun@lindeni.com
 *
 * Create Date:
 *      2019/08/08
 *
 * History:
 *
 */

#ifndef __VDEC_WRAPPER_H_
#define __VDEC_WRAPPER_H_

#include <pthread.h>

#ifdef __cplusplus
extern "C" {
#endif

#include "lindcomponent.h"

typedef long vdec_wrapper_t;

typedef struct _video_picture_t
{
    int             nID;
    int             nStreamIndex;
    int             ePixelFormat;
    int             nWidth;
    int             nHeight;
    int             nLineStride;
    char*           pData0;
    char*           pData1;
    char*           pData2;
    char*           pData3;
    unsigned long   phyYBufAddr;
    unsigned long   phyCBufAddr;
    unsigned long   phyRBufAddr;
    unsigned long   bKeyFrame;

    int             nLeftOffset;
    int             nTopOffset;
    int             nRightOffset;
    int             nBottomOffset;

    void*           pPriv;          // picture pointer to aw decoder
} video_picture_t;

typedef enum _codec_format_e
{
    CODEC_FORMAT_UNKNOWN    = 0,
    CODEC_FORMAT_H264,
    CODEC_FORMAT_H265,
    CODEC_FORMAT_XVID,
    CODEC_FORMAT_MPEG2,
    CODEC_FORMAT_JPEG,
} codec_format_e;

typedef struct _vdec_configs_t
{
    codec_format_e      format;
    int                 width;
    int                 height;
    int                 frame_rate;
    int                 frame_duration;
    int                 aspect_ratio;
    char *              p_specific_data;
    int                 specific_data_len;

    /*
     * decode rotate degree
     */
    rotate_degree_e     rotate;

    /*
     * 0: do not scale
     * 1: 1/2
     * 2: 1/4
     * 3: 1/8
     */
    int                 scale_ratio;
} vdec_configs_t;

/**
 * Create a vdec_wrapper_t object.
 *
 * @param
 * @return
 *    NULL: create failed
 *    not NULL: the vdec_wrapper_t object
 */
vdec_wrapper_t vdec_wrapper_create();

/**
 * 1. Initialize the hw video decoder.
 * 2. If 'p_data_consumer' be set not NULL, it will create a thread to decode video
 *      stream and render picture.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 *    p_config[in]: set video parameters, video format must be set.
 *    p_data_consumer[in]: not used, allways set to NULL.
 * @return
 *    0 success, < 0 error
 */
int     vdec_wrapper_init(vdec_wrapper_t vdec_handle, vdec_configs_t * p_config, /* for debug */void * p_data_consumer);

/**
 * 1. wait video decode thread end.
 * 2. release resources.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 * @return
 */
void    vdec_wrapper_destory(vdec_wrapper_t vdec_handle);

/**
 * Call to start decoding.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 * @return
 */
void    vdec_wrapper_start(vdec_wrapper_t vdec_handle);

/**
 * Call to stop decoding.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 * @return
 */
void    vdec_wrapper_stop(vdec_wrapper_t vdec_handle);

/**
 * @Deprecated, Use method {@link #vdec_wrapper_send_data2()} instead.
 *
 * Send video bit stream to decoder.
 * !!! App must check the return value. If it return -1, app should try again to avoid
 * discard the bit stream, it may cause playing mossica.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 *    p_buf[in]: the video bit stream to be decoded.
 *    size[in]: the size of 'p_buf'.
 *    nalu_start_bit[in]: a nalu start flag, if this is a nalu start, set to true(1).
 *    nalu_end_bit[in]: a nalu end flag, if this is a nalu end, set to true(1).
 *      If demux allways send a complete frame once, so they are allways be set to true(1).
 * @return
 *    0 success, < 0 error
 */
int     vdec_wrapper_send_data(vdec_wrapper_t vdec_handle,
                               void * data, int size,
                               int nalu_start_bit, int nalu_end_bit);

/**
 * Send video bit stream to decoder.
 * !!! App must check the return value. If it return -1, app should try again to avoid
 * discard the bit stream, it may cause playing mossica.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 *    data [in]: the video bit stream to be decoded.
 *    size [in]: the size of 'data'.
 *    pts  [in]: the pts of this frame.
 * @return
 *    0 success, < 0 error
 */
int     vdec_wrapper_send_data2(vdec_wrapper_t vdec_handle,
                               void * data, int size, int64_t pts);

/**
 * App get a picture decoded from the decoder.
 * App should allways check the return value, and better also check the 'p_pic'.
 * !!! This version we consider the receive and release logic like this:
 *          receive id: 0 1 2 3 4 5 6 7 8
 *      and release id:   0 1 2 3 4 5 6 7, the last frame will be release in stop function calling.
 *    Frame release will be called in receive calling.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 *    p_pic[out]: a frame decoded, app can send it to display or others.
 * @return
 *    0 success, < 0 error
 */
/**
 * @Deprecated, Use method {@link #vdec_wrapper_receive_frame2()} instead.
 */
int     vdec_wrapper_receive_frame(vdec_wrapper_t vdec_handle, video_picture_t * p_pic);
int     vdec_wrapper_receive_frame2(vdec_wrapper_t vdec_handle, av_frame2_t * p_pic);

/**
 * !!! As discribed in vdec_wrapper_receive_frame(), this function is not used now.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 *    p_pic[in]: a frame to be released.
 * @return
 *    0 success, < 0 error
 */
/**
 * @Deprecated, Use method {@link #vdec_wrapper_release_frame2()} instead.
 */
int     vdec_wrapper_release_frame(vdec_wrapper_t vdec_handle, video_picture_t * p_pic);
int     vdec_wrapper_release_frame2(vdec_wrapper_t vdec_handle, av_frame2_t * p_pic);

/**
 * Reset the decoder, it will be called in playing seek.
 *
 * @param
 *    p_vdec_wrapper[in]: the vdec_wrapper_t handle.
 * @return
 */
void    vdec_wrapper_flush(vdec_wrapper_t vdec_handle);

#ifdef __cplusplus
}
#endif

#endif

